package tech

import "ssp/set"

func (g *Grid) HiddenPairHouse(house *House) (bool, []*Result) {
	return g.hiddenHouse(house, 2)
}

func (s *Solve) HiddenPair(g *Grid) (bool, []*Result) {
	return g.useTechInAllHouse(g.HiddenPairHouse)
}

func (g *Grid) HiddenTripleHouse(house *House) (bool, []*Result) {
	return g.hiddenHouse(house, 3)
}

func (s *Solve) HiddenTriple(g *Grid) (bool, []*Result) {
	return g.useTechInAllHouse(g.HiddenTripleHouse)
}

func (g *Grid) HiddenQuadrupleHouse(house *House) (bool, []*Result) {
	return g.hiddenHouse(house, 4)
}

func (s *Solve) HiddenQuadruple(g *Grid) (bool, []*Result) {
	return g.useTechInAllHouse(g.HiddenQuadrupleHouse)
}

func (g *Grid) hiddenHouse(house *House, hiddenCount int) (used bool, results []*Result) {
	unSolvedCells := getUnsolvedCells(house.cells[:])
	for _, cells := range combine(unSolvedCells, hiddenCount) {
		hiddenCands := set.NewSet()
		otherCands := set.NewSet()
		for _, cell := range unSolvedCells {
			if cell.isMemberOf(cells) {
				hiddenCands = hiddenCands.Union(cell.cands)
			} else {
				otherCands = otherCands.Union(cell.cands)
			}
		}
		hiddenCands = hiddenCands.Diff(otherCands)
		if hiddenCands.Count() != hiddenCount {
			continue
		}
		if ok, rmCells := canClearupHidden(cells, hiddenCands); ok {
			used = true
			if OUTPUTRESULT {
				result := new(Result)
				result.addRemoved(set.NewFull().Diff(hiddenCands), rmCells)
				group := result.getHelpCandsGroup()
				group.add(hiddenCands, cells)
				result.addHelpHouses([]*House{house})
				result.setStrategyName(house.KindName() + " Hidden " + SUBSET_NAMES[hiddenCount-2])
				results = append(results, result)
			}
			if CHANGE {
				removeCands(set.NewFull().Diff(hiddenCands), rmCells)
				//fmt.Println(results[len(results)-1])
			}
			if !EXHAUSTIVE {
				return
			}
		}
	}
	return
}

func canClearupHidden(hiddenCells []*Cell, cands set.Set) (ok bool, rmCells []*Cell) {
	butCands := set.NewFull().Diff(cands)
	for _, cell := range hiddenCells {
		if cell.canRemoveCands(butCands) {
			rmCells = append(rmCells, cell)
			ok = true
		}
	}
	return
}
